#pragma once

#include "QueryBuilder.h"
#include "DatabaseError.h"
#include <string>
#include <vector>
#include <map>
#include <functional>
#include <type_traits>
#include <memory>
#include <chrono>
#include <algorithm>

/**
 * @brief CLink 命名空间包含所有 CloudLinker 框架的组件
 */
namespace CLink
{
/**
 * @brief Db 命名空间包含数据库操作相关的类和函数
 */
namespace Db
{

/**
 * @brief 数据库字段类型枚举
 * 
 * 定义了数据库表字段可用的数据类型
 */
enum class FieldType {
    INTEGER,    ///< 整数类型
    FLOAT,      ///< 浮点数类型
    TEXT,       ///< 文本类型
    DATETIME,   ///< 日期时间类型
    BOOLEAN,    ///< 布尔类型
    BLOB        ///< 二进制大对象类型
};

/**
 * @brief 数据库字段定义结构体
 * 
 * 用于定义数据库表的字段属性，包括名称、类型、约束等
 */
struct CLINK_CLASS FieldDefinition {
    std::string name;        ///< 字段名称
    FieldType type;          ///< 字段类型
    bool nullable = false;   ///< 是否允许为空
    bool primary = false;    ///< 是否为主键
    bool autoIncrement = false; ///< 是否自动递增
    std::string defaultValue; ///< 默认值
    size_t length = 0;       ///< 字段长度，主要用于VARCHAR类型
};

/**
 * @brief 模型关系类型枚举
 * 
 * 定义了模型之间可能的关系类型
 */
enum class RelationType {
    HAS_ONE,      ///< 一对一关系，当前模型拥有一个关联模型
    HAS_MANY,     ///< 一对多关系，当前模型拥有多个关联模型
    BELONGS_TO,   ///< 从属关系，当前模型属于另一个模型
    MANY_TO_MANY  ///< 多对多关系，通过中间表连接
};

/**
 * @brief 模型关系定义结构体
 * 
 * 用于定义模型之间的关系，包括关系类型、外键等
 */
struct CLINK_CLASS RelationDefinition {
    RelationType type;        ///< 关系类型
    std::string model;        ///< 关联模型的名称
    std::string foreignKey;   ///< 外键名称
    std::string localKey;     ///< 本地键名称
    std::string pivotTable;   ///< 中间表名称（用于多对多关系）
    std::string pivotForeignKey; ///< 中间表中的外键（用于多对多关系）
    std::string pivotLocalKey;   ///< 中间表中的本地键（用于多对多关系）
};

/**
 * @brief 验证规则结构体
 * 
 * 用于定义模型字段的验证规则
 */
struct CLINK_CLASS ValidationRule {
    std::string field;  ///< 需要验证的字段名
    std::vector<std::function<bool(const std::string&)>> validators; ///< 验证函数集合，每个函数返回验证是否通过
    std::string message; ///< 验证失败时的错误消息
};

class DatabaseManager;

/**
 * @brief ORM模型基类
 * 
 * 所有数据库模型类都应该继承自此类，提供了ORM的基本功能
 */
class CLINK_CLASS Model {
public:
    using Ptr = std::shared_ptr<Model>;
    Model() = default;
    /**
     * @brief 默认构造函数
     */
    Model(std::shared_ptr<DatabaseManager>  _db);
    
    /**
     * @brief 虚析构函数
     */
    virtual ~Model() = default;

    /**
     * @brief 创建模型实例
     * @return 返回新创建的模型实例指针
     */
    //virtual Ptr create() = 0;

    /**
     * @brief 获取模型对应的数据库表名
     * @return 表名
     */
    virtual std::string getTableName() const = 0;
    
    /**
     * @brief 获取模型的主键名
     * @return 主键名
     */
    virtual std::string getPrimaryKey() const = 0;
    
    /**
     * @brief 获取模型的字段定义
     * @return 字段定义列表
     */
    virtual std::vector<FieldDefinition> getFields() const = 0;
    
    /**
     * @brief 获取模型的关系定义
     * @return 关系定义映射，键为关系名，值为关系定义
     */
    virtual std::map<std::string, RelationDefinition> getRelations() const {
        return {};
    }
    
    /**
     * @brief 获取模型的验证规则
     * @return 验证规则列表
     */
    virtual std::vector<ValidationRule> getValidationRules() const {
        return {};
    }

    /**
     * @brief 保存模型到数据库
     * @return 保存是否成功
     */
    bool save();
    
    /**
     * @brief 更新模型属性
     * @param attributes 要更新的属性映射
     * @return 更新是否成功
     */
    bool update(const std::map<std::string, std::string>& attributes);
    
    /**
     * @brief 从数据库中删除模型
     * @return 删除是否成功
     */
    bool remove();
    
    /**
     * @brief 获取创建表的SQL语句
     * @tparam T 模型类型，必须继承自Model
     * @return 创建表的SQL语句
     */
    template<typename T>
    static std::string getCreateTableSQL(std::shared_ptr<DatabaseManager> _db);
    
    /**
     * @brief 创建模型对应的数据库表
     * @tparam T 模型类型，必须继承自Model
     * @return 创建是否成功
     */
    template<typename T>
    static bool createTable(std::shared_ptr<DatabaseManager> _db);
    
    /**
     * @brief 删除模型对应的数据库表
     * @tparam T 模型类型，必须继承自Model
     * @return 删除是否成功
     */
    template<typename T >
    static bool dropTable(std::shared_ptr<DatabaseManager> _db);
    
    /**
     * @brief 检查模型对应的表是否存在
     * @tparam T 模型类型，必须继承自Model
     * @return 表是否存在
     */
    template<typename T>
    static bool tableExists(std::shared_ptr<DatabaseManager> _db);
    
    /**
     * @brief 获取模型的所有记录
     * @tparam T 模型类型，必须继承自Model
     * @return 模型实例列表
     */
    template<typename T>
    static std::vector<std::shared_ptr<T>> all(std::shared_ptr<DatabaseManager> _db);
    
    /**
     * @brief 通过ID查找模型
     * @tparam T 模型类型，必须继承自Model
     * @param id 要查找的ID
     * @return 找到的模型实例，如果未找到则返回nullptr
     */
    template<typename T>
    static std::shared_ptr<T> find(const std::string& id, std::shared_ptr<DatabaseManager> _db);
    
    /**
     * @brief 根据条件查询模型
     * @tparam T 模型类型，必须继承自Model
     * @param column 查询的列名
     * @param op 操作符类型
     * @param value 比较值
     * @return 符合条件的模型实例列表
     */
    template<typename T>
    static std::vector<std::shared_ptr<T>> where(const std::string& column, OperatorType op, const std::string& value, std::shared_ptr<DatabaseManager> _db);
    
    /**
     * @brief 根据条件查询模型
     * @tparam T 模型类型，必须继承自Model
     * @param column 查询的列名
     * @param value 比较值
     * @return 符合条件的模型实例列表
     */
    template<typename T>
    static std::vector<std::shared_ptr<T>> where(const std::string& column, const std::string& value, std::shared_ptr<DatabaseManager> _db);

    /**
     * @brief 获取一对多关系的关联模型
     * @tparam T 关联模型类型，必须继承自Model
     * @param foreignKey 外键名称
     * @return 关联模型实例列表
     */
    template<typename T>
    std::vector<std::shared_ptr<T>> hasMany(const std::string& foreignKey);
    
    /**
     * @brief 获取一对一关系的关联模型
     * @tparam T 关联模型类型，必须继承自Model
     * @param foreignKey 外键名称
     * @return 关联模型实例，如果未找到则返回nullptr
     */
    template<typename T>
    std::shared_ptr<T> hasOne(const std::string& foreignKey);
    
    /**
     * @brief 获取从属关系的关联模型
     * @tparam T 关联模型类型，必须继承自Model
     * @param foreignKey 外键名称
     * @return 关联模型实例，如果未找到则返回nullptr
     */
    template<typename T>
    std::shared_ptr<T> belongsTo(const std::string& foreignKey);
    
    /**
     * @brief 获取多对多关系的关联模型
     * @tparam T 关联模型类型，必须继承自Model
     * @param pivotTable 中间表名称
     * @param foreignPivotKey 中间表中的外键名称
     * @param localPivotKey 中间表中的本地键名称
     * @return 关联模型实例列表
     */
    template<typename T>
    std::vector<std::shared_ptr<T>> belongsToMany(const std::string& pivotTable,
                                                    const std::string& foreignPivotKey,
                                                    const std::string& localPivotKey);
    
    /**
     * @brief 通过关系名称获取多个关联模型
     * @tparam T 关联模型类型，必须继承自Model
     * @param relationName 关系名称
     * @return 关联模型实例列表
     */
    template<typename T>
    std::vector<std::shared_ptr<T>> getRelated(const std::string& relationName);
    
    /**
     * @brief 通过关系名称获取单个关联模型
     * @tparam T 关联模型类型，必须继承自Model
     * @param relationName 关系名称
     * @return 关联模型实例，如果未找到则返回nullptr
     */
    template<typename T>
    std::shared_ptr<T> getRelatedOne(const std::string& relationName);

    /**
     * @brief 设置模型属性
     * @param key 属性名
     * @param value 属性值
     */
    void setAttribute(const std::string& key, const std::string& value);
    
    /**
     * @brief 获取模型属性
     * @param key 属性名
     * @return 属性值
     */
    std::string getAttribute(const std::string& key) const;
    
    /**
     * @brief 检查模型是否有指定属性
     * @param key 属性名
     * @return 是否存在该属性
     */
    bool hasAttribute(const std::string& key) const;
    
    /**
     * @brief 验证模型数据
     * @return 验证是否通过
     */
    bool validate();
    
    /**
     * @brief 获取验证错误信息
     * @return 错误信息列表
     */
    std::vector<std::string> getErrors() const;

    std::shared_ptr<DatabaseManager> getDb()const { return _db; }

protected:
    std::map<std::string, std::string> _attributes;  ///< 模型属性映射
    
    std::vector<std::string> _errors;  ///< 验证错误信息
    
    bool _isNewRecord = true;  ///< 是否为新记录

	std::shared_ptr<CLink::Db::DatabaseManager> _db;  ///< 数据库管理器实例

    /**
     * @brief 必填验证器
     * @param value 要验证的值
     * @return 验证是否通过
     */
    static bool required(const std::string& value) {
        return !value.empty();
    }
    
    /**
     * @brief 邮箱格式验证器
     * @param value 要验证的值
     * @return 验证是否通过
     */
    static bool email(const std::string& value) {
        return value.find('@') != std::string::npos;
    }
    
    /**
     * @brief 数字验证器
     * @param value 要验证的值
     * @return 验证是否通过
     */
    static bool numeric(const std::string& value) {
        return std::all_of(value.begin(), value.end(), 
                          [](char c) { return std::isdigit(c); });
    }
    
    /**
     * @brief 长度验证器
     * @param value 要验证的值
     * @param min 最小长度
     * @param max 最大长度
     * @return 验证是否通过
     */
    static bool length(const std::string& value, size_t min, size_t max) {
        return value.length() >= min && value.length() <= max;
    }
};

/**
 * @brief 模型工厂类
 * 
 * 用于创建和初始化模型实例
 * 
 * @tparam T 模型类型，必须继承自Model
 */
template<typename T>
class ModelFactory {
public:
    /**
     * @brief 创建模型实例并设置属性
     * @param attributes 初始属性映射
     * @return 创建的模型实例
     */
    static std::shared_ptr<T> create(std::shared_ptr<DatabaseManager> _db, const std::map<std::string, std::string>& attributes) {
        auto model = std::make_shared<T>(_db);
        for (const auto& [key, value] : attributes) {
            model->setAttribute(key, value);
        }
        return model;
    }
};

class Timestamps {
public:
    virtual ~Timestamps() = default;
    
    void setCreatedAt() {
        _attributes["created_at"] = getCurrentTimestamp();
    }
    
    void setUpdatedAt() {
        _attributes["updated_at"] = getCurrentTimestamp();
    }

protected:
    std::map<std::string, std::string> _attributes;
    
    static std::string getCurrentTimestamp() {
        auto now = std::chrono::system_clock::now();
        auto now_c = std::chrono::system_clock::to_time_t(now);
        char buf[64];
        std::strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", std::localtime(&now_c));
        return buf;
    }
};

template<typename T>
std::vector<std::shared_ptr<T>> Model::hasMany(const std::string& foreignKey) {
    if (_isNewRecord) {
        return {};
    }
    
    auto builder = _db->getQueryBuilder();
    
    T dummy(_db);
    builder.from(dummy.getTableName())
           .where(foreignKey, _attributes[getPrimaryKey()]);
    
    std::vector<std::shared_ptr<T>> results;
    try {
        auto resultSet = _db->query(builder);
        auto data = resultSet.toMap();
        
        results.reserve(data.size());
        for (const auto& row : data) {
            auto model = std::make_shared<T>(_db);
            for (const auto& [key, value] : row) {
                model->setAttribute(key, value);
            }
            model->_isNewRecord = false;
            results.push_back(model);
        }
    } catch (const DatabaseException& e) {
        // 查询失败时返回空结果
    }
    
    return results;
}

template<typename T>
std::shared_ptr<T> Model::hasOne(const std::string& foreignKey) {
    if (_isNewRecord) {
        return nullptr;
    }
    
    auto builder = _db->getQueryBuilder();
    
    T dummy(_db);
    builder.from(dummy.getTableName())
           .where(foreignKey, _attributes[getPrimaryKey()])
           .limit(1);
    
    try {
        auto resultSet = _db->query(builder);
        auto data = resultSet.toMap();
        
        if (!data.empty()) {
            auto model = std::make_shared<T>(_db);
            for (const auto& [key, value] : data[0]) {
                model->setAttribute(key, value);
            }
            model->_isNewRecord = false;
            return model;
        }
    } catch (const DatabaseException& e) {
        // 查询失败时返回nullptr
    }
    
    return nullptr;
}

template<typename T>
std::shared_ptr<T> Model::belongsTo(const std::string& foreignKey) {
    if (_isNewRecord || !hasAttribute(foreignKey)) {
        return nullptr;
    }
    
    auto builder = _db->getQueryBuilder();
    
    T dummy(_db);
    builder.from(dummy.getTableName())
           .where(dummy.getPrimaryKey(), _attributes[foreignKey])
           .limit(1);
    
    try {
        auto resultSet = _db->query(builder);
        auto data = resultSet.toMap();
        
        if (!data.empty()) {
            auto model = std::make_shared<T>(_db);
            for (const auto& [key, value] : data[0]) {
                model->setAttribute(key, value);
            }
            model->_isNewRecord = false;
            return model;
        }
    } catch (const DatabaseException& e) {
        // 查询失败时返回nullptr
    }
    
    return nullptr;
}

template<typename T>
std::vector<std::shared_ptr<T>> Model::belongsToMany(const std::string& pivotTable,
                                                    const std::string& foreignPivotKey,
                                                    const std::string& localPivotKey) {
    if (_isNewRecord) {
        return {};
    }
    
    auto builder = _db->getQueryBuilder();
    
    T dummy(_db);
    builder.from(dummy.getTableName())
           .join(pivotTable,
                 pivotTable + "." + foreignPivotKey,
                 CLink::Db::OperatorType::EQUAL,
                 dummy.getTableName() + "." + dummy.getPrimaryKey())
           .where(pivotTable + "." + localPivotKey,
                 _attributes[getPrimaryKey()]);
    
    std::vector<std::shared_ptr<T>> results;
    try {
        auto resultSet = _db->query(builder);
        auto data = resultSet.toMap();
        
        results.reserve(data.size());
        for (const auto& row : data) {
            auto model = std::make_shared<T>(_db);
            for (const auto& [key, value] : row) {
                // 只设置目标模型的属性，忽略中间表的属性
                if (key.find(dummy.getTableName()) == 0) {
                    model->setAttribute(key.substr(dummy.getTableName().length() + 1), value);
                }
            }
            model->_isNewRecord = false;
            results.push_back(model);
        }
    } catch (const DatabaseException& e) {
        // 查询失败时返回空结果
    }
    
    return results;
}

// 通过关系名称获取关联模型
template<typename T>
std::vector<std::shared_ptr<T>> Model::getRelated(const std::string& relationName) {
    auto relations = getRelations();
    auto it = relations.find(relationName);
    if (it == relations.end()) {
        return {};
    }
    
    const auto& relation = it->second;
    
    switch (relation.type) {
        case RelationType::HAS_MANY:
            return hasMany<T>(relation.foreignKey);
            
        case RelationType::MANY_TO_MANY:
            return belongsToMany<T>(
                relation.pivotTable,
                relation.pivotForeignKey,
                relation.pivotLocalKey
            );
            
        default:
            return {};
    }
}

// 通过关系名称获取单个关联模型
template<typename T>
std::shared_ptr<T> Model::getRelatedOne(const std::string& relationName) {
    auto relations = getRelations();
    auto it = relations.find(relationName);
    if (it == relations.end()) {
        return nullptr;
    }
    
    const auto& relation = it->second;
    
    switch (relation.type) {
        case RelationType::HAS_ONE:
            return hasOne<T>(relation.foreignKey);
            
        case RelationType::BELONGS_TO:
            return belongsTo<T>(relation.foreignKey);
            
        default:
            return nullptr;
    }
}

// 静态查询方法（模板）实现
template<typename T>
std::vector<std::shared_ptr<T>> Model::all(std::shared_ptr<DatabaseManager> _db) {
    T dummy(_db);
    auto builder = _db->getQueryBuilder();
    
    builder.from(dummy.getTableName());
    
    std::vector<std::shared_ptr<T>> results;
    try {
        auto resultSet = _db->query(builder);
        auto data = resultSet.toMap();
        
        results.reserve(data.size());
        for (const auto& row : data) {
            auto model = std::make_shared<T>(_db);
            for (const auto& [key, value] : row) {
                model->setAttribute(key, value);
            }
            model->_isNewRecord = false;
            results.push_back(model);
        }
    } catch (const DatabaseException& e) {
        // 查询失败时返回空结果
    }
    
    return results;
}

template<typename T>
std::shared_ptr<T> Model::find(const std::string& id, std::shared_ptr<DatabaseManager> _db) {
    T dummy(_db);
    auto builder = _db->getQueryBuilder();
    
    try {
        builder.from(dummy.getTableName())
            .where(dummy.getPrimaryKey(), id)
            .orderBy(dummy.getPrimaryKey())
               .limit(1);
        
        auto resultSet = _db->query(builder);
        auto data = resultSet.toMap();
        
        if (!data.empty()) {
            auto model = std::make_shared<T>(_db);
            for (const auto& [key, value] : data[0]) {
                model->setAttribute(key, value);
            }
            model->_isNewRecord = false;
            return model;
        }
    } catch (const DatabaseException& e) {
        // 查询失败时返回nullptr
    }
    
    return nullptr;
}

template<typename T>
std::vector<std::shared_ptr<T>> Model::where(const std::string& column, const std::string& value, std::shared_ptr<DatabaseManager> _db)
{
	return where<T>(column, OperatorType::EQUAL, value);
}

template<typename T>
std::vector<std::shared_ptr<T>> Model::where(const std::string& column, OperatorType op, const std::string& value, std::shared_ptr<DatabaseManager> _db)
{
    T dummy(_db);
    auto builder = _db->getQueryBuilder();
    
    // 获取字段定义，以确定字段类型
    auto fields = dummy.getFields();
    bool isNumericField = false;
    
    // 查找匹配的字段并确定其类型
    for (const auto& field : fields) {
        if (field.name == column) {
            // 检查字段是否为数字类型
            isNumericField = (field.type == FieldType::INTEGER || field.type == FieldType::FLOAT);
            break;
        }
    }
    
    // 根据字段类型构建查询
    if (isNumericField) {
        // 对于数字类型，直接使用值（不加引号）
        // 尝试将字符串转换为数字
        try {
            // 检查值是否为整数
            if (value.find('.') == std::string::npos) {
                // 整数
                long long intValue = std::stoll(value);
                builder.from(dummy.getTableName())
                       .whereRaw(column + " " + operatorToString(op) + " " + value);
            } else {
                // 浮点数
                double floatValue = std::stod(value);
                builder.from(dummy.getTableName())
                       .whereRaw(column + " " + operatorToString(op) + " " + value);
            }
        } catch (const std::exception&) {
            // 转换失败，回退到字符串处理
            builder.from(dummy.getTableName())
                   .where(column, op, value);
        }
    } else {
        // 对于非数字类型，使用标准where方法（会自动添加引号）
        builder.from(dummy.getTableName())
               .where(column, op, value);
    }
    
    std::vector<std::shared_ptr<T>> results;
    try {
        auto resultSet = _db->query(builder);
        auto data = resultSet.toMap();
        
        results.reserve(data.size());
        for (const auto& row : data) {
            auto model = std::make_shared<T>(_db);
            for (const auto& [key, value] : row) {
                model->setAttribute(key, value);
            }
            model->_isNewRecord = false;
            results.push_back(model);
        }
    } catch (const DatabaseException& e) {
        // 查询失败时返回空结果
    }
    
    return results;
}

// 表操作静态方法（模板）实现
template<typename T>
std::string Model::getCreateTableSQL(std::shared_ptr<DatabaseManager> _db) {
    T dummy(_db);
    std::stringstream sql;
    sql << "CREATE TABLE IF NOT EXISTS " << dummy.getTableName() << " (";
    
    auto fields = dummy.getFields();
    std::vector<std::string> primaryKeys;
    
    for (size_t i = 0; i < fields.size(); ++i) {
        const auto& field = fields[i];
        
        sql << field.name << " ";
        
        // 字段类型
        switch (field.type) {
            case FieldType::INTEGER:
                sql << "INTEGER";
                break;
            case FieldType::FLOAT:
                sql << "REAL";
                break;
            case FieldType::TEXT:
                if (field.length > 0) {
                    sql << "VARCHAR(" << field.length << ")";
                } else {
                    sql << "TEXT";
                }
                break;
            case FieldType::DATETIME:
                sql << "DATETIME";
                break;
            case FieldType::BOOLEAN:
                sql << "BOOLEAN";
                break;
            case FieldType::BLOB:
                sql << "BLOB";
                break;
        }
        
        // 收集主键字段
        if (field.primary) {
            primaryKeys.push_back(field.name);
            
            // 如果是自增主键，仍然需要在字段定义中声明
            if (field.autoIncrement) {
                sql << " PRIMARY KEY AUTOINCREMENT";
            }
        }
        
        if (!field.nullable) {
            sql << " NOT NULL";
        }
        
        if (!field.defaultValue.empty()) {
            sql << " DEFAULT " << field.defaultValue;
        }
        
        // 添加逗号，除非是最后一个字段且没有主键需要声明
        if (i < fields.size() - 1 || (!primaryKeys.empty() && !fields[i].autoIncrement)) {
            sql << ", ";
        }
    }
    
    // 在表定义末尾添加主键声明（如果有主键且不是自增主键）
    if (!primaryKeys.empty()) {
        bool hasAutoIncrement = false;
        for (const auto& field : fields) {
            if (field.primary && field.autoIncrement) {
                hasAutoIncrement = true;
                break;
            }
        }
        
        // 只有当没有自增主键或有多个主键时才添加PRIMARY KEY声明
        if (!hasAutoIncrement || primaryKeys.size() > 1) {
            // 如果最后一个字段后面已经添加了逗号，就不需要再添加
            sql << "PRIMARY KEY (";
            for (size_t i = 0; i < primaryKeys.size(); ++i) {
                sql << primaryKeys[i];
                if (i < primaryKeys.size() - 1) {
                    sql << ", ";
                }
            }
            sql << ")";
        }
    }
    
    sql << ")";
    return sql.str();
}

template<typename T>
bool Model::createTable(std::shared_ptr<DatabaseManager> _db) {
    try {
        std::string sql = getCreateTableSQL<T>(_db);
        _db->execute(sql);
        return true;
    } catch (const DatabaseException& e) {
        // 静态方法不能访问 _errors，所以我们只能返回 false
        return false;
    }
}

template<typename T>
bool Model::dropTable(std::shared_ptr<DatabaseManager> _db) {
    try {
        T dummy(_db);
        std::string sql = "DROP TABLE IF EXISTS " + dummy.getTableName();
        _db->execute(sql);
        return true;
    } catch (const DatabaseException& e) {
        // 静态方法不能访问 _errors，所以我们只能返回 false
        return false;
    }
}

template<typename T>
bool Model::tableExists(std::shared_ptr<DatabaseManager> _db) {
    try {
        T dummy(_db);
        return _db->tableExists(dummy.getTableName());
    } catch (const DatabaseException& e) {
        // 静态方法不能访问 _errors，所以我们只能返回 false
        return false;
    }
}

} // namespace Db
} // namespace CLink